<?php
namespace App\Controllers;

use CodeIgniter\Controller;

define('IS_INSTALL', true);

class Install extends Controller
{

    public $db;
    private $lock;
    private $code = 'rter4hel70'; //安装码

    public function __construct()
    {

        helper(['ams', 'cookie', 'security', 'filesystem']);
        $code = \Config\Services::request()->getGet('code');
        if (!$code || ($this->code != $code)) {
            exit('请输入安装码');
        }

        $this->renderer = \Config\Services::renderer();
        $this->db = \Config\Database::connect('default');
        $this->lock = WRITEPATH . 'install.locks';
        is_file($this->lock) && exit('您已经安装过了，如需重新安装，请删除cache/install.lock文件');

        if (version_compare(PHP_VERSION, '7.3.0') < 0) {
            exit('当前环境PHP' . PHP_VERSION . ',要求PHP7.3以上');
        }
    }

    public function index()
    {
        $step = max(1, (int) $this->request->getGet('step'));

        switch ($step) {

            case 1:
                break;

            case 2:

                $check_pass = true;

                $writeAble = $this->_checkFileRight();
                $lowestEnvironment = $this->_getLowestEnvironment();
                $currentEnvironment = $this->_getCurrentEnvironment();
                $recommendEnvironment = $this->_getRecommendEnvironment();

                foreach ($currentEnvironment as $key => $value) {
                    if (false !== strpos($key, '_ischeck') && false === $value) {
                        $check_pass = false;
                    }
                }
                foreach ($writeAble as $value) {
                    if (false === $value) {
                        $check_pass = false;
                    }
                }

                //清除垃圾文件
                $this->_clean_writepath_dir('session');
                $this->_clean_writepath_dir('uploads');
                $this->_clean_writepath_dir('views');
                $this->_clean_writepath_dir('module');
                $this->_clean_writepath_dir('logs');
                $this->_clean_writepath_dir('config');
                $this->_clean_writepath_dir('debugbar');

                $this->renderer->setData([
                    'writeAble' => $writeAble,
                    'check_pass' => $check_pass,
                    'lowestEnvironment' => $lowestEnvironment,
                    'currentEnvironment' => $currentEnvironment,
                    'recommendEnvironment' => $recommendEnvironment,
                ]);
                break;

            case 3:

                if ($_POST) {
                    $data = $this->request->getPost('data');

                    $systemModel = model('App\Models\SystemModel');
                    $rs = $systemModel->install($data);

                    if ($rs['code']) {
                        exit(ams_json($rs));
                    }
                    exit(ams_json(0, '安装成功', url('install/index', ['code' => $this->code, 'step' => $step + 1])));
                }
                break;

            case 4:

                $log = [];
                $sql = file_get_contents(WRITEPATH . 'install/install.sql');
                preg_match_all('/`\{dbprefix\}(.+)`/U', $sql, $match);
                if ($match) {
                    $log = array_unique($match[1]);
                }
                $this->renderer->setData([
                    'log' => implode('<ciams>', $log),
                ]);
                break;

            case 5:
                $success = cache('login_success');
                $this->renderer->setData([
                    'success' => $success,
                ]);
                file_put_contents(WRITEPATH . 'install.locks', time());
                $this->_clean_writepath_dir('cache');
                break;
        }

        $vdata = ['code' => $this->code, 'step' => $step];
        return view('step_' . $step . '.html', $vdata);
    }

    /**
     * 获得当前的环境信息
     *
     * @return array
     */
    private function _getCurrentEnvironment()
    {
        $lowestEnvironment = $this->_getLowestEnvironment();
        $space = floor(@disk_free_space(WEBPATH) / (1024 * 1024));
        $space = $space ? $space . 'M' : 'unknow';
        $currentUpload = ini_get('file_uploads') ? ini_get('upload_max_filesize') : 'unknow';
        $upload_ischeck = intval($currentUpload) >= intval($lowestEnvironment['upload']) ? true : false;
        $space_ischeck = intval($space) >= intval($lowestEnvironment['space']) ? true : false;
        $version_ischeck = version_compare(phpversion(), $lowestEnvironment['version']) < 0 ? false : true;
        $pdo_mysql_ischeck = extension_loaded('pdo_mysql');
        if (function_exists('mysql_get_client_info')) {
            $mysql = mysql_get_client_info();
            $mysql_ischeck = true;
        } elseif (function_exists('mysqli_get_client_info')) {
            $mysql = mysqli_get_client_info();
            $mysql_ischeck = true;
        } elseif ($pdo_mysql_ischeck) {
            $mysql_ischeck = true;
            $mysql = 'unknow';
        } else {
            $mysql_ischeck = false;
            $mysql = 'unknow';
        }
        if (function_exists('gd_info')) {
            $gdinfo = gd_info();
            $gd = $gdinfo['GD Version'];
            $gd_ischeck = version_compare($lowestEnvironment['gd'], $gd) < 0 ? false : true;
        } else {
            $gd_ischeck = false;
            $gd = 'unknow';
        }
        return [
            'gd' => $gd,
            'os' => PHP_OS,
            'json' => function_exists('json_encode'),
            'space' => $space,
            'mysql' => $mysql,
            'upload' => $currentUpload,
            'version' => phpversion(),
            'pdo_mysql' => $pdo_mysql_ischeck,
            'gd_ischeck' => $gd_ischeck,
            'os_ischeck' => true,
            'space_ischeck' => $space_ischeck,
            'mysql_ischeck' => $mysql_ischeck,
            'version_ischeck' => $version_ischeck,
            'upload_ischeck' => $upload_ischeck,
            'pdo_mysql_ischeck' => $pdo_mysql_ischeck,
        ];
    }

    //删除某个目录里的文件
    private function _clean_writepath_dir($dirname = '')
    {
        $not = ['index.html', '.htaccess', 'install.locks'];
        if (!$dirname || !in_array($dirname, ['session', 'uploads', 'debug', 'apps', 'views', 'logs', 'debugbar', 'cache'])) {
            return false;
        }
        $dirpath = WRITEPATH . $dirname . '/';
        $files = scandir($dirpath);
        if ($files) {
            foreach ($files as $file) {
                if ($file != "." && $file != ".." && !in_array($file, $not)) {
                    $fullpath = $dirpath . "/" . $file;
                    if (!is_dir($fullpath)) {
                        @unlink($fullpath);
                    } else {
                        @rmdir($fullpath);
                    }
                }
            }
        }
    }

    /**
     * 获取推荐的环境配置信息
     *
     * @return array
     */
    private function _getRecommendEnvironment()
    {
        return [
            'os' => 'Linux',
            'gd' => '>2.0.28',
            'json' => '支持',
            'mysql' => '>5.x.x',
            'space' => '>50M',
            'upload' => '>2M',
            'version' => '>7.3.x',
            'pdo_mysql' => '支持',
        ];
    }

    /**
     * 获取环境的最低配置要求
     *
     * @return array
     */
    private function _getLowestEnvironment()
    {
        return [
            'os' => '不限制',
            'gd' => '2.0',
            'json' => '必须支持',
            'space' => '50M',
            'mysql' => '4.2',
            'upload' => '不限制',
            'version' => '7.3.0',
            'pdo_mysql' => '不限制',
        ];
    }

    /**
     * 检查目录权限
     *
     * @return array
     */
    private function _checkFileRight()
    {

        $files_writeble[] = ROOTPATH . 'writable/';

        $files_writeble = array_unique($files_writeble);
        sort($files_writeble);
        $writable = [];

        foreach ($files_writeble as $file) {
            $key = str_replace([WEBPATH, ROOTPATH], '', $file);
            $isWritable = $this->_checkWriteAble($file) ? true : false;
            if ($isWritable) {
                $flag = false;
                foreach ($writable as $k => $v) {
                    if (0 === strpos($key, $k)) {
                        $flag = true;
                    }
                }
                $flag || $writable[$key] = $isWritable;
            } else {
                $writable[$key] = $isWritable;
            }
        }
        return $writable;
    }

    /**
     * 检查目录可写
     *
     * @param string $pathfile
     * @return boolean
     */
    private function _checkWriteAble($pathfile)
    {
        if (!$pathfile) {
            return false;
        }
        $isDir = in_array(substr($pathfile, -1), ['/', '\\']) ? true : false;
        if ($isDir) {
            if (is_dir($pathfile)) {
                mt_srand((double) microtime() * 1000000);
                $pathfile = $pathfile . 'ams_' . uniqid(mt_rand()) . '.tmp';
            } elseif (@mkdir($pathfile)) {
                return self::_checkWriteAble($pathfile);
            } else {
                return false;
            }
        }
        @chmod($pathfile, 0777);
        $fp = @fopen($pathfile, 'ab');
        if ($fp === false) {
            return false;
        }
        fclose($fp);
        $isDir && @unlink($pathfile);
        return true;
    }
}
